/**
2	 * Copyright (C) 2011 JogAmp Community. All rights reserved.
3	 *
4	 * Permission is hereby granted, free of charge, to any person obtaining a
5	 * copy of this software and associated documentation files (the "Software"),
6	 * to deal in the Software without restriction, including without limitation
7	 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8	 * and/or sell copies of the Software, and to permit persons to whom the
9	 * Software is furnished to do so, subject to the following conditions:
10	 *
11	 * The above copyright notice and this permission notice shall be included
12	 * in all copies or substantial portions of the Software.
13	 *
14	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15	 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17	 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18	 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19	 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20	 */
21	package com.jogamp.opengl.test.junit.jogl.demos.es2;
22	
23	import com.jogamp.common.nio.Buffers;
24	import com.jogamp.newt.Window;
25	import com.jogamp.newt.event.KeyAdapter;
26	import com.jogamp.newt.event.KeyEvent;
27	import com.jogamp.newt.event.KeyListener;
28	import com.jogamp.newt.event.MouseAdapter;
29	import com.jogamp.newt.event.MouseEvent;
30	import com.jogamp.newt.event.MouseListener;
31	import com.jogamp.opengl.test.junit.jogl.demos.GearsObject;
32	import com.jogamp.opengl.util.PMVMatrix;
33	import com.jogamp.opengl.util.glsl.ShaderCode;
34	import com.jogamp.opengl.util.glsl.ShaderProgram;
35	import com.jogamp.opengl.util.glsl.ShaderState;
36	import java.nio.FloatBuffer;
37	import javax.media.opengl.GL;
38	import javax.media.opengl.GL2ES2;
39	import javax.media.opengl.GLAutoDrawable;
40	import javax.media.opengl.GLContext;
41	import javax.media.opengl.GLEventListener;
42	import javax.media.opengl.GLProfile;
43	import javax.media.opengl.GLUniformData;
44	
45	import junit.framework.Assert;
46	
47	/**
48	 * GearsES2.java <BR>
49	 * @author Brian Paul (converted to Java by Ron Cemer and Sven Gothel) <P>
50	 */
51	public class GearsES2 implements GLEventListener {
52	    private final FloatBuffer lightPos = Buffers.newDirectFloatBuffer( new float[] { 5.0f, 5.0f, 10.0f } );
53	   
54	    private ShaderState st = null;
55	    private PMVMatrix pmvMatrix = null;
56	    private GLUniformData pmvMatrixUniform = null;
57	    private GLUniformData colorU = null;
58	    private float view_rotx = 20.0f, view_roty = 30.0f, view_rotz = 0.0f;
59	    private GearsObjectES2 gear1=null, gear2=null, gear3=null;
60	    private float angle = 0.0f;
61	    private int swapInterval = 0;
62	    private boolean initialized = false;
63	
64	    private int prevMouseX, prevMouseY;
65	
66	    public GearsES2(int swapInterval) {
67	        this.swapInterval = swapInterval;
68	    }
69	
70	    public GearsES2() {
71	        this.swapInterval = 1;
72	    }
73	
74	    public void setGears(GearsObjectES2 g1, GearsObjectES2 g2, GearsObjectES2 g3) {
75	        gear1 = g1;
76	        gear2 = g2;
77	        gear3 = g3;
78	    }
79	
80	    /**
81	     * @return gear1
82	     */
83	    public GearsObjectES2 getGear1() { return gear1; }
84	
85	    /**
86	     * @return gear2
87	     */
88	    public GearsObjectES2 getGear2() { return gear2; }
89	
90	    /**
91	     * @return gear3
92	     */
93	    public GearsObjectES2 getGear3() { return gear3; }
94	
95	
96	    public void init(GLAutoDrawable drawable) {
97	        System.err.println(Thread.currentThread()+" GearsES2.init ...");
98	        Assert.assertEquals("already init", false, initialized);
99	        initialized = true;
100	        GL2ES2 gl = drawable.getGL().getGL2ES2();
101	
102	        System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
103	        System.err.println("INIT GL IS: " + gl.getClass().getName());
104	        System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
105	        System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
106	        System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
107	
108	        gl.glEnable(GL.GL_CULL_FACE);
109	        gl.glEnable(GL.GL_DEPTH_TEST);
110	       
111	        st = new ShaderState();
112	        st.setVerbose(true);
113	        final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
114	                "shader", "shader/bin", "gears");
115	        final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
116	                "shader", "shader/bin", "gears");
117	        final ShaderProgram sp0 = new ShaderProgram();
118	        sp0.add(gl, vp0, System.err);
119	        sp0.add(gl, fp0, System.err);
120	        st.attachShaderProgram(gl, sp0);
121	        st.useProgram(gl, true);
122	        // Use debug pipeline
123	        // drawable.setGL(new DebugGL(drawable.getGL()));
124	
125	        pmvMatrix = new PMVMatrix();
126	        st.attachObject("pmvMatrix", pmvMatrix);
127	        pmvMatrixUniform = new GLUniformData("pmvMatrix", 4, 4, pmvMatrix.glGetPMvMvitMatrixf()); // P, Mv, Mvi and Mvit
128	        st.ownUniform(pmvMatrixUniform);
129	        st.uniform(gl, pmvMatrixUniform);
130	
131	        GLUniformData lightU = new GLUniformData("lightPos", 3, lightPos);
132	        st.ownUniform(lightU);
133	        st.uniform(gl, lightU);
134	
135	        colorU = new GLUniformData("color", 4, GearsObject.red);
136	        st.ownUniform(colorU);
137	        st.uniform(gl, colorU);
138	
139	        if(null == gear1) {
140	            gear1 = new GearsObjectES2(1.0f, 4.0f, 1.0f, 20, 0.7f, pmvMatrix, pmvMatrixUniform, colorU);
141	            System.err.println("gear1 created: "+gear1);
142	        } else {
143	            gear1 = new GearsObjectES2(gear1, pmvMatrix, pmvMatrixUniform, colorU);
144	            System.err.println("gear1 reused: "+gear1);
145	        }
146	                   
147	        if(null == gear2) {
148	            gear2 = new GearsObjectES2(0.5f, 2.0f, 2.0f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU);
149	            System.err.println("gear2 created: "+gear2);
150	        } else {
151	            gear2 = new GearsObjectES2(gear2, pmvMatrix, pmvMatrixUniform, colorU);
152	            System.err.println("gear2 reused: "+gear2);
153	        }
154	               
155	        if(null == gear3) {
156	            gear3 = new GearsObjectES2(1.3f, 2.0f, 0.5f, 10, 0.7f, pmvMatrix, pmvMatrixUniform, colorU);
157	            System.err.println("gear3 created: "+gear3);
158	        } else {
159	            gear3 = new GearsObjectES2(gear3, pmvMatrix, pmvMatrixUniform, colorU);
160	            System.err.println("gear3 reused: "+gear3);
161	        }               
162	       
163	        // MouseListener gearsMouse = new TraceMouseAdapter(new GearsMouseAdapter());
164	        MouseListener gearsMouse = new GearsMouseAdapter();   
165	        KeyListener gearsKeys = new GearsKeyAdapter();
166	
167	        if (drawable instanceof Window) {
168	            Window window = (Window) drawable;
169	            window.addMouseListener(gearsMouse);
170	            window.addKeyListener(gearsKeys);
171	        } else if (GLProfile.isAWTAvailable() && drawable instanceof java.awt.Component) {
172	            java.awt.Component comp = (java.awt.Component) drawable;
173	            new com.jogamp.newt.event.awt.AWTMouseAdapter(gearsMouse).addTo(comp);
174	            new com.jogamp.newt.event.awt.AWTKeyAdapter(gearsKeys).addTo(comp);
175	        }
176	        st.useProgram(gl, false);
177	       
178	        gl.setSwapInterval(swapInterval);
179	       
180	        System.err.println(Thread.currentThread()+" GearsES2.init FIN");
181	    }
182	
183	    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
184	        System.err.println(Thread.currentThread()+" GearsES2.reshape "+x+"/"+y+" "+width+"x"+height+", swapInterval "+swapInterval);
185	        Assert.assertEquals("not init or already disposed", true, initialized);
186	        GL2ES2 gl = drawable.getGL().getGL2ES2();
187	
188	        float h = (float)height / (float)width;
189	
190	        st.useProgram(gl, true);
191	        pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION);
192	        pmvMatrix.glLoadIdentity();
193	        pmvMatrix.glFrustumf(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
194	        pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW);
195	        pmvMatrix.glLoadIdentity();
196	        pmvMatrix.glTranslatef(0.0f, 0.0f, -40.0f);
197	        st.uniform(gl, pmvMatrixUniform);
198	        st.useProgram(gl, false);
199	       
200	        System.err.println(Thread.currentThread()+" GearsES2.reshape FIN");
201	    }
202	
203	    public void dispose(GLAutoDrawable drawable) {
204	        System.err.println(Thread.currentThread()+" GearsES2.dispose ... ");
205	        Assert.assertEquals("not init or already disposed", true, initialized);
206	        initialized = false;
207	        GL2ES2 gl = drawable.getGL().getGL2ES2();
208	        st.useProgram(gl, false);
209	        gear1.destroy(gl);
210	        gear1 = null;
211	        gear2.destroy(gl);
212	        gear2 = null;
213	        gear3.destroy(gl);
214	        gear3 = null;       
215	        pmvMatrix = null;
216	        colorU = null;       
217	        st.destroy(gl);
218	        st = null;
219	        System.err.println(Thread.currentThread()+" GearsES2.dispose FIN");
220	    }
221	
222	    public void display(GLAutoDrawable drawable) {
223	        Assert.assertEquals("not init or already disposed", true, initialized);
224	        // Turn the gears' teeth
225	        angle += 2.0f;
226	
227	        // Get the GL corresponding to the drawable we are animating
228	        GL2ES2 gl = drawable.getGL().getGL2ES2();
229	
230	        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
231	
232	        // Special handling for the case where the GLJPanel is translucent
233	        // and wants to be composited with other Java 2D content
234	        if (GLProfile.isAWTAvailable() &&
235	            (drawable instanceof javax.media.opengl.awt.GLJPanel) &&
236	            !((javax.media.opengl.awt.GLJPanel) drawable).isOpaque() &&
237	            ((javax.media.opengl.awt.GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
238	          gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
239	        } else {
240	          gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
241	        }
242	
243	        st.useProgram(gl, true);
244	        pmvMatrix.glPushMatrix();
245	        pmvMatrix.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
246	        pmvMatrix.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
247	        pmvMatrix.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);
248	
249	        gear1.draw(gl, -3.0f, -2.0f,  1f * angle -    0f, GearsObject.red);
250	        gear2.draw(gl,  3.1f, -2.0f, -2f * angle -  9.0f, GearsObject.green);
251	        gear3.draw(gl, -3.1f,  4.2f, -2f * angle - 25.0f, GearsObject.blue);   
252	        pmvMatrix.glPopMatrix();
253	        st.useProgram(gl, false);
254	    }
255	
256	    class GearsKeyAdapter extends KeyAdapter {     
257	        public void keyPressed(KeyEvent e) {
258	            int kc = e.getKeyCode();
259	            if(KeyEvent.VK_LEFT == kc) {
260	                view_roty -= 1;
261	            } else if(KeyEvent.VK_RIGHT == kc) {
262	                view_roty += 1;
263	            } else if(KeyEvent.VK_UP == kc) {
264	                view_rotx -= 1;
265	            } else if(KeyEvent.VK_DOWN == kc) {
266	                view_rotx += 1;
267	            }
268	        }
269	    }
270	
271	    class GearsMouseAdapter extends MouseAdapter {
272	        public void mousePressed(MouseEvent e) {
273	            prevMouseX = e.getX();
274	            prevMouseY = e.getY();
275	        }
276	
277	        public void mouseReleased(MouseEvent e) {
278	        }
279	
280	        public void mouseDragged(MouseEvent e) {
281	            int x = e.getX();
282	            int y = e.getY();
283	            int width=0, height=0;
284	            Object source = e.getSource();
285	            if(source instanceof Window) {
286	                Window window = (Window) source;
287	                width=window.getWidth();
288	                height=window.getHeight();
289	            } else if (GLProfile.isAWTAvailable() && source instanceof java.awt.Component) {
290	                java.awt.Component comp = (java.awt.Component) source;
291	                width=comp.getWidth();
292	                height=comp.getHeight();
293	            } else {
294	                throw new RuntimeException("Event source neither Window nor Component: "+source);
295	            }
296	            float thetaY = 360.0f * ( (float)(x-prevMouseX)/(float)width);
297	            float thetaX = 360.0f * ( (float)(prevMouseY-y)/(float)height);
298	
299	            prevMouseX = x;
300	            prevMouseY = y;
301	
302	            view_rotx += thetaX;
303	            view_roty += thetaY;
304	        }
305	    }
306	}